
#include "datparser.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <fcntl.h>
#include <unistd.h>

#include <sys/stat.h>

static int dat_add_last(struct dat_stu *head, char *label, int l_size, char *value, int v_size)
{
	struct dat_node *new = NULL;
	struct dat_node *last = NULL;

	if(NULL != head && NULL != label && 0 < l_size && NULL != value && 0 <= v_size)
	{
		new = (struct dat_node *)calloc(1, sizeof(*new));
		if(NULL != new)
		{
			memset(new, 0, sizeof(*new));
			strncpy(new->label, label, l_size);
			strncpy(new->value, value, v_size);
			
			if(NULL != head->first)
			{
				last = head->first;
			
				while(NULL != last->next)
				{
					last = last->next;
				}
				last->next = new;
				new->next = NULL;
			}
			else
			{
				head->first = new;
				new->next = NULL;
			}
			head->node++;
		}
	}
	return 0;
}

static int dat_free_last(struct dat_stu *head, struct dat_node *node)
{
	if(NULL != node)
	{
		if(NULL != node->next)
		{
			dat_free_last(head, node->next);
		}
		head->node--;
		node->next = NULL;
		free(node);
	}
	return 0;
}

static int dat_free_node(struct dat_stu *head)
{
	return dat_free_last(head, head->first);
}

static char *find_char(char *buffer, char ch)
{
	while(NULL != buffer)
	{
		if(ch == *buffer)
		{
			return buffer;
		}
		buffer++;
	}
	return NULL;
}

static char *find_next_equal(char *buffer)
{
	return find_char(buffer, '=');
}

static char *find_next_lf(char *buffer)
{
	return find_char(buffer, '\n');
}

static int dat_to_node(struct dat_stu *head, char *buffer)
{
	const char *flag = "Default\n";
	char *section = NULL;

	char *start = NULL;
	char *equal = NULL; 
	char *end = NULL;
	
	//char test[32] = {0};
	
	if(NULL != head)
	{
		section = strstr(buffer, flag);

		if(NULL != section)
		{
			section += strlen(flag);
			start = section;
			
			while(NULL != start && 0 != *start)
			{
				equal = find_next_equal(start);
				end = find_next_lf(start);
				
				if(NULL != start && NULL != equal && NULL != end)
				{
					if(start < equal && equal < end)
					{
						//strncpy(test, start, equal - start);
						//printf("%s=", test);
						//memset(test, 0, sizeof(test));
						//strncpy(test, equal + 1, end - equal - 1);
						//printf("%s\n", test);
						dat_add_last(head, start, equal - start, equal + 1, end - equal - 1);
					}
				}
				start = end + 1;
			}
			return 0;
		}
	}
	return -1;
}

static int dat_load_node(struct dat_stu *head)
{
	int ret = 0;
	FILE *pf = NULL;
	
	char *buffer = NULL;
	
	if(NULL != head && 0 < head->filesize)
	{
		pf = fopen(head->filename, "r");

		if(NULL != pf)
		{
			buffer = (char *)calloc(1, head->filesize + 10);
			if(NULL != buffer)
			{
				if(head->filesize == fread(buffer, 1, head->filesize, pf))
				{
					ret = dat_to_node(head, buffer);
					free(buffer);
					return ret;
				}
				free(buffer);
			}
		}
	}
	return -1;
}

static off_t get_file_size(struct dat_stu *head)
{
	struct stat statbuff;
	if(0 == stat((const char *)head->filename, &statbuff))
	{
		return statbuff.st_size;
	}
	return 0;
}

static int check_file_exist(char *filename)
{
	if(0 == access(filename, F_OK) && 0 == access(filename, R_OK) && 0 == access(filename, W_OK))
	{
		return 0;
	}
	return -1;
}

void dat_dump(struct dat_stu *head)
{
	struct dat_node *tmp = NULL;
	
	if(NULL != head)
	{
		tmp = head->first;
		while(NULL != tmp)
		{
			printf("%s=%s\n", tmp->label, tmp->value);
			tmp = tmp->next;
		}
	}
}

int dat_set_lable(struct dat_stu *head, char *label, char *value, int v_size)
{
	struct dat_node *tmp = NULL;
	
	if(NULL != head && NULL != label && NULL != value && 0 <= v_size)
	{
		printf("\033[0;31m#####\033[0m%s\t%s\t%d\n", label, value, v_size);
		tmp = head->first;
		while(NULL != tmp)
		{
			if(0 == strcmp(label, tmp->label))
			{
				memset(tmp->value, 0, sizeof(tmp->value));
				strncpy(tmp->value, value, v_size);
				//printf("%p\t%p\n", tmp, tmp->next);
				return 0;
			}
			tmp = tmp->next;
		}
	}
	return -1;
}

void dat_free(struct dat_stu **head)
{
	if(NULL != head && NULL != *head)
	{
		free(*head);
		*head = NULL;
	}
}

int dat_save(char *filename, struct dat_stu *head)
{
	FILE *pf = NULL;
	struct dat_node *tmp = NULL;
	
	if(NULL != filename && NULL != head)
	{
		pf = fopen(filename, "w");
		
		if(NULL != pf)
		{
			fprintf(pf, "#The word of \"Default\" must not be removed\nDefault\n");
			tmp = head->first;
			while(NULL != tmp)
			{
				fprintf(pf, "%s=%s\n", tmp->label, tmp->value);
				fflush(pf);
				tmp = tmp->next;
			}
			fclose(pf);
			return 0;
		}
	}
	return -1;
}

int dat_load(char *filename, struct dat_stu **head)
{
	struct dat_stu *tmp = NULL;
	if(NULL != filename && NULL != head)
	{
		if(0 == check_file_exist(filename))
		{
			if(NULL != *head)
			{
				dat_free(head);
			}
			tmp = (struct dat_stu *)calloc(1, sizeof(*tmp));
			if(NULL != tmp)
			{
				strncpy(tmp->filename, filename, sizeof(tmp->filename));
				tmp->filesize = get_file_size(tmp);
				tmp->node = 0;
				tmp->first = NULL;
				
				if(0 == dat_load_node(tmp))
				{
					*head = tmp;
					return 0;
				}
				dat_free_node(tmp);
				dat_free(&tmp);
			}
		}
	}
	return -1;
}